/**
 * Created by YangYan on 2016/5/8.
 */
(function () {
    function factorial(x){
        if(x <= 1) return 1;
        return x*factorial(x-1);
    };
   // console.log(factorial(5));
    var f=function fact(x){
        if(x<1) return 1;
        else return x*fact(x-1);
    };
   // console.log(f);
    var f1=(function fact(x){
        if(x<1) return 1;
        else return x*fact(x-1)})(5);
   // console.log(f1);
    var calculator={
        operand1:1,
        operand2:1,
        add:function(){
            this.result=this.operand1+this.operand2;//如果不加this要报错
        }
    };
    //console.log(calculator.add());//undefined
    //console.log(calculator.result);//2
    // o["m"](x,y); o[m](x,y);
    // a[0](x);
    // f().m();

    var o={
        m:function(){
            var self=this;
            //console.log(this === o);
            f();
            function f(){
              // console.log(this === o);
              //  console.log(self === o);
            }
        }
    };
    o.m();
    function getPropertyNames(o,a){
        if(a === undefined) a=[];
        for(var property in o) a.push(property);
        return a;
    };
    var a=getPropertyNames(o);
    getPropertyNames(calculator,a);//将p的属性追加到数组a中；

    function f(x,y,z) {
        if(arguments.length !=3){
            throw new Error("function f called with "+arguments.length+"  arguments,but it expects 3 arguments.");
        }
    };
    function max(/* ... */){
        var max=Number.NEGATIVE_INFINITY;
        //console.log(max);
        for(var i=0;i<arguments.length;i++){
            if(arguments[i] > max) max=arguments[i];
            return max;
        }
    };
    var largest=max(2,10,100,2,3,1000,4,5,10000,6);
    //console.log(largest);//书上说是10000，在chrome上得2
    var factorial=function(x){
        if(x <= 1){
            return 1;
        };
        return x*arguments.callee(x-1);
    };
   // console.log(factorial(6));
    var o={square:function (x){return x*x}};
    var y= o.square(5);
    //console.log(y);
    // function operate(operator,operand1,operand2){
    //     return operate(operand1,operand2);
    // };
    // var i=operate(add,operate(add,2,3),operate(multiply,4,5));
    // console.log(i);

    var operators={
        add:function (x,y) {
            return x+y;
        },
        subtract:function(x,y){
            return x-y;
        },
        multiply:function(x,y){
            return x*y;
        },
        divide:function (x,y) {
            return x/y;
        },
        pow:Math.pow
    };
    function operate2(operation,operand1,operand2) {
        if(typeof operators[operation] === "function"){
            return operators[operation](operand1,operand2);
        }else {
            throw "unknown operator";
        }
    };
    var j=operate2("add","hello",operate2("add"," ","world"));
    var k=operate2("pow",10,2);
   // console.log(j);console.log(k);
    //特定场景下返回带补丁的extend()版本
    var extend=(function(){
        for(var p in {toString: null}){
            return function extend(o){
                for(var i=1;i<arguments.length;i++){
                    var source=arguments[i];
                    for(var prop in source) o[prop]=source[prop];
                }
                return o;
            };
        };//
        return function patched_extend(o){
            for(var j=0;j<protoprops.length;j++){
                prop=protoprops[j];
                if(source.hasOwnProperty(prop)) o[prop]=source[prop];
                for(var j=0;j<protoprops.length;j++){
                    prop = protoprops[j];
                    if(source.hasOwnProperty(prop)) o[prop]=source[prop];
                }
            }
            return o;
        };

        var protoprops = ["toString","valueOf","constructor","hasOwnProperty","isPrototypeOf"];

    }());
   // console.log(extend);
    //
    var scope="global scope";
    function checkscope(){
        var scope="local scope";
        function f(){return scope;}
        return f;
    };
   // console.log(checkscope()());
    var calculator={
        operand1:1,
        operand2:1,
        add:function(){
            this.result=this.operand1+this.operand2;
        }
    };
   // console.log(calculator.add());//只是执行方法而已，并不会返回什么值。
   // console.log(calculator.result);
   var o={
       m:function(){
           var self=this;
           console.log(this===o);
           f();
           function f(){
               console.log(this===o);
               console.log(self===o);
           }
       }
   };
    //o.m();
    //可选形参,调用这个函数可以传入1或2个形参
    function getPropertyNames(o,/* optional*/ a){
        if(a === undefined) a=[];
        for(var property in o) a.push(property);
        return a;
    };
    var a=getPropertyNames(o);//将o的属性存储在新数组中
    var p={};
    getPropertyNames(p,a);//将p的属性追加到新数组中

    var scope="global scope";
    function checkscope(){
        var scope="local scope";
        function f(){return scope;}
        return f();
    };
   // console.log(checkscope());

    var scope="global scope";
    function checkscope(){
        var scope="local scope";
        function f(){return scope;}
        return f;
    };
    //console.log(checkscope()());
    var uniqueInteger=(function(){
        var counter=0;
        return function(){return counter++;}
    }());
    function counter(){
        var n=0;
        return {
          count:function(){return n++;},
          reset:function () {
              n=0;
          }
        };
    };
    var c=counter(),d=counter();
   // console.log(d.count);//返回的是一段函数代码
    //console.log(d.count);
    //console.log(c.count);
    function counter(n) {
        return {
            get count(){return n++;},
            set count(m){
                if(m >= n) n=m;
                else throw Error("count can only be set to a larger value");
            }
        };
    };
    var c=counter(1000);
   // console.log(c.count);
    //console.log(c.count);

    c.count=2000;
    //console.log(c.count);//2000
    //c.count=2000;报错
    //-----------------------------------------------
    function addPrivateProperty(o,name,predicate){
        var value;
        o["get" +name]=function(){
            return value;
        };
        o["set" +name]=function(v){
            if(predicate && !predicate(v)){
                throw Error("set "+name+":invalid value "+v)
            }else{ value=v;}
        }
    };
    var o={};
    addPrivateProperty(o,"Name",function(x){return typeof x=="string";});
    o.setName("Frank");//设置属性值
   // console.log(o.getName());//得到属性值
    //o.setName(0);//试图设置一个错误类型的值
    //--------------------------------------------
    function constfunc(v) {
        return function(){return v;}
    };
    var funcs=[];
    for(i=0;i<10;i++) funcs[i]=constfunc(i);
   //console.log(funcs[5]());console.log(funcs[4]());

    function constfuncs(){
        var funcs1=[];
        for(var i=0;i<10;i++){
            funcs1[i]=function(){return i;}
        };
        return funcs1;
    };
    var funcs1=constfuncs();
   // console.log(funcs1[5]());//10
    //--------------------------------------
    function check(args){
        var actual=args.length;
        var expected=args.callee.length;
       // console.log(actual +":"+expected);
        if(actual !== expected){
            throw Error("throw exception!");
        }
    };
    function f(x,y,z){
        check(arguments);
        return x+y+z;
    };
    //---------------------------------
    function f(y){
        return this.x+y;
    };
    var o={x:1};
    var g=f.bind(o);
   // console.log(g(2));
    function binds(f,o){
        if(f.bind) return f.bind(o);
        else return function(){return f.apply(o,arguments);}
    };

    var sum=function(x,y){return x+y;};
    var succ=sum.bind(null,1);
   // console.log(succ(2));

    function f(f,z){return this.x+y+z;};
    var g=f.bind({x:1},2);
   // console.log(g(3));
//---------------------------------------------------------------
    var scope = "global";
    function constructFunction(){
        var scope="local";
        return new Function("return scope;");
    }
  //  console.log(constructFunction()());
    var sum=function(x,y){return x+y;};
    var square=function (x) {
        return x*x;
    };
    var data=[1,1,3,5,5];
    var mean=data.reduce(sum)/data.length;
    var deviations=data.map(function(x){return x-mean;});
    var stddev=Math.sqrt(deviations.map(square).reduce(sum)/(data.length-1));
  //  console.log(deviations);console.log(stddev);
    //----------------------------------------------
    function not(f){
        return function(){
            var result=f.apply(this,arguments);
            return !result;
        };
    };
    var even=function(x){
        return x%2 ===0;
    };
    var odd=not(even);
    //console.log([1,1,3,5,5].every(odd));
    //---------------------------------------------
    var map=Array.prototype.map
        ?function(a,f){return a.map(f);}
        :function(a,f){
          var results=[];
          for(var i=0,len=a.length;i<len;i++){
              if(i in a) results[i]=f.call(null,a[i],i,a);
          }
          return results;
    };
    function mapper(f){
        return function (a) {
            return map(a,f);
        }
    };
    var increment=function(x){return x+1;};
    var incrementer=mapper(increment);
    //console.log(incrementer([1,2,3]));
    function compose(f,g){
        return function(){
            return f.call(this,g.apply(this,arguments));
        }
    };
    var square= function(x){return x*x;};
    var sum=function(x,y){return x+y;};
    var squareofsum=compose(square,sum);
    //console.log(squareofsum(2,3));
    //-----------------------------------------------------
    if(!Function.prototype.bind){
        Function.prototype.bind=function(o/*,args*/){
            var self=this,boundArgs=arguments;
            return function(){
                var args=[],i;
                for(i=0;i<boundArgs.length;i++) args.push(boundArgs[i]);
                for(i=0;i<arguments.length;i++) args.push(arguments[i]);
                return self.apply(o,args)
            }
        }
    }
    //----------------
    function add(a,b){return a+b;}
    function sub(a,b){return a-b;}
    var res=add.call(sub,2,1);
   // console.log(res);---------------
    function Animal(){
        this.name="Animal";
        this.showName=function(){
            console.log(this.name);
        }
    };
    function Cat(){
        Animal.call(this,name)
    };
   // var animal=new Animal();
    var cat=new Cat("Black Cat");
    console.log(cat.showName);








})()
